﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.ComponentModel;
using System.Xml.Serialization;
using Dare.Utilities.Data;

namespace Dare.Utilities
{
    public sealed class EnumUtil
    {
        /// <summary>
        /// 获取枚举类子项描述信息
        /// </summary>
        /// <param name="enumSubitem">枚举类子项</param>        
        public static string GetEnumDescription(Enum enumSubitem)
        {
            FieldInfo fieldinfo = enumSubitem.GetType().GetField(enumSubitem.ToString());
            Object[] objs = fieldinfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (objs == null || objs.Length == 0)
            {
                return enumSubitem.ToString();
            }
            else
            {
                DescriptionAttribute da = (DescriptionAttribute)objs[0];
                return da.Description;
            }
        }

        /// <summary>
        /// 获取枚举类子项描述信息
        /// </summary>
        /// <param name="enumSubitem">枚举类子项</param>        
        public static object GetEnumAttribute(Enum enumSubitem, Type attributeType)
        {
            FieldInfo fieldinfo = enumSubitem.GetType().GetField(enumSubitem.ToString());
            Object[] objs = fieldinfo.GetCustomAttributes(attributeType, false);
            if (objs == null || objs.Length == 0)
            {
                return null;
            }
            else
            {
                return objs[0];
            }
        }

        /// <summary>
        /// 获取枚举自定义属性
        /// </summary>
        public static T GetEnumAttribute<T>(Enum e)
            where T : Attribute
        {
            FieldInfo fieldinfo = e.GetType().GetField(e.ToString());
            object[] objs = fieldinfo.GetCustomAttributes(typeof(T), false);
            if (objs == null || objs.Length == 0)
            {
                return null;
            }
            else
            {
                return objs[0] as T;
            }
        }

        private static Dictionary<Type, Dictionary<string, object>> cachedGetEnumFromXmlEnumAttributeNames = new Dictionary<Type, Dictionary<string, object>>();
        public static T? GetEnumFromXmlEnumAttributeName<T>(string val)
             where T : struct
        {
            if (val == null) val = String.Empty;
            else val = val.Trim().ToLower();

            if (!cachedGetEnumFromXmlEnumAttributeNames.ContainsKey(typeof(T)))
            {
                Array values = Enum.GetValues(typeof(T));
                Dictionary<string, object> dict = new Dictionary<string, object>(values.Length);
                for (int i = 0; i < values.Length; i++)
                {
                    XmlEnumAttribute attr = GetEnumAttribute<XmlEnumAttribute>(values.GetValue(i) as Enum);
                    dict[(attr == null ? values.GetValue(i).ToString().ToLower() : attr.Name.ToLower())] = values.GetValue(i);
                }
                cachedGetEnumFromXmlEnumAttributeNames[typeof(T)] = dict;
            }

            if (cachedGetEnumFromXmlEnumAttributeNames[typeof(T)].ContainsKey(val))
            {
                return (T)cachedGetEnumFromXmlEnumAttributeNames[typeof(T)][val];
            }
            else
            {
                return null;
            }
        }

        public static T GetEnumFromXmlEnumAttributeName<T>(string val, T defaultValue)
                         where T : struct
        {
            T? result = GetEnumFromXmlEnumAttributeName<T>(val);
            return result.HasValue ? result.Value : defaultValue;
        }


        private static Dictionary<Type, Dictionary<string, object>> cachedGetEnumFromDbEnumAttributeNames = new Dictionary<Type, Dictionary<string, object>>();
        public static T? GetEnumFromDbEnumAttributeName<T>(string val)
             where T : struct
        {
            if (val == null) val = String.Empty;
            else val = val.Trim().ToLower();

            if (!cachedGetEnumFromDbEnumAttributeNames.ContainsKey(typeof(T)))
            {
                Array values = Enum.GetValues(typeof(T));
                Dictionary<string, object> dict = new Dictionary<string, object>(values.Length);
                for (int i = 0; i < values.Length; i++)
                {
                    DbEnumAttribute attr = GetEnumAttribute<DbEnumAttribute>(values.GetValue(i) as Enum);
                    dict[(attr == null ? values.GetValue(i).ToString().ToLower() : attr.Name.ToLower())] = values.GetValue(i);
                }
                cachedGetEnumFromDbEnumAttributeNames[typeof(T)] = dict;
            }

            if (cachedGetEnumFromDbEnumAttributeNames[typeof(T)].ContainsKey(val))
            {
                return (T)cachedGetEnumFromDbEnumAttributeNames[typeof(T)][val];
            }
            else
            {
                return null;
            }
        }

        public static T GetEnumFromDbEnumAttributeName<T>(string val, T defaultValue)
                         where T : struct
        {
            T? result = GetEnumFromDbEnumAttributeName<T>(val);
            return result.HasValue ? result.Value : defaultValue;
        }

        public static T? GetEnum<T>(string val)
            where T : struct
        {
            if (String.IsNullOrEmpty(val)) return null;

            int num = 0;
            if (int.TryParse(val, out num))
            {
                if (Enum.IsDefined(typeof(T), num))
                {
                    return (T)Enum.ToObject(typeof(T), num);
                }
                else
                {
                    return null;
                }
            }
            else
            {
                try
                {
                    return (T)Enum.Parse(typeof(T), val, true);
                }
                catch
                {
                    return null;
                }
            }
        }
    }
}
